/**
 * 为便于管理，事件预先配置
 * 事件名 : 方法名(onXXXX)
 */
const EVENTS = {
  // ========================================
  // UI类
  // 加载
  loading: 'onLoading',
  // Notice(Toast)
  noticed: 'onNoticed',
  // ========================================
  //
  logout: 'onLogout',
  navopen: 'onNavigatorOpen',
  navclosed: 'onNavigatorClosed',
  notifyreceived: 'onNotifyReceived',
}

/**
 * 构造
 */
function VcEvent() {
  let _EVENT_MAP = {}
  for (let m in EVENTS) {
    if (EVENTS[m].indexOf('on') !== 0) throw new Error('事件方法必须以on开头')
    _EVENT_MAP[m] = {
      m: EVENTS[m],
      listeners: []
    }
  }
  this._EVENT_MAP = _EVENT_MAP
}

/**
 * 监听事件
 */
VcEvent.prototype.on = function (event, vm, listener) {
  this._EVENT_MAP[event].listeners.push({ vm, listener })
}

/**
 * 移除事件
 */
VcEvent.prototype.off = function (event, vm, listener) {
  if (!this._EVENT_MAP[event]) return
  let nlisteners = []
  let listeners = this._EVENT_MAP[event].listeners
  for (let l in listeners) {
    if (listeners[l].vm === vm && listeners[l].listener === listener) continue
    nlisteners[l] = listeners[l]
  }
  this._EVENT_MAP[event] = nlisteners
}

/**
 * 派发事件
 */
VcEvent.prototype.emit = function (event, params) {
  if (!this._EVENT_MAP[event]) return
  let listeners = this._EVENT_MAP[event].listeners
  for (let l in listeners) {
    listeners[l].listener.call(listeners[l].vm, params)
  }
}

VcEvent.install = function (Vue) {

  Vue.prototype.$vcevent = Vue.prototype.$vcevent || new VcEvent()

  Vue.mixin({
    created: function () {
      // 扫描实例options的onXXX
      let that = this
      that.$vcevent._root = that.$root
      that.__vcevts = {}
      for (let m in EVENTS) {
        if (this.$options[EVENTS[m]]) {
          that.__vcevts[m] = EVENTS[m]
          that.$vcevent.on(m, that, that.$options[EVENTS[m]])
        }
      }
    },
    destroyed: function () {
      let that = this
      let events = that.__vcevts || {}
      for (let event in events) {
        that.$vcevent.off(event, that, events[event])
      }
    }
  })
}

export default VcEvent
